/* -*- Mode: c; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil; -*- */
/*
  RefObject (http://code.google.com/p/refobject/)
  Copyright (C) 2010-2011 MIURA Shirow (sharow)
*/

#include "RefBaseInternal.h"
#include "RefModuleInternal.h"

typedef struct {
    RefObject *mRefAllocator;
} RefModule;

static RefTypeObject *gModuleTypeObject = NULL;
static RefObject *gModule = NULL;

static void
RefModule_Destructor(RefObject *aRefObject)
{
    RefObject *refallocator;
    refallocator = ((RefModule *)RefObject_GetObject(aRefObject))->mRefAllocator;
    RefAllocator_Free(refallocator, aRefObject);
    RefObject_DecRef(refallocator);
}

static RefObject *
RefModule_Create(RefObject *aRefAllocator)
{
    RefObject *refobj;
    RefModule *module;
    if (aRefAllocator && RefAllocator_IsValid(aRefAllocator)) {
    } else {
        return NULL;
    }
    refobj = RefAllocator_Alloc(aRefAllocator, RefObject_SizeOf() + sizeof(*module));
    module = RefObject_Construct(refobj, &gModuleTypeObject, RefModule_Destructor);
    module->mRefAllocator = aRefAllocator;
    RefObject_IncRef(aRefAllocator);
    return refobj;
}

RefObject *
RefModule_GetAllocator(RefObject *aRefObject)
{
    return ((RefModule *)RefObject_GetObject(aRefObject))->mRefAllocator;
}

RefObject *
RefModule_GetSingletonModule(void)
{
    return gModule;
}

RefObject *
RefModule_GetSingletonAllocator(void)
{
    return RefModule_GetAllocator(RefModule_GetSingletonModule());
}


int
RefModule_Initialize(RefObject *aRefAllocator)
{
    if (gModule) {
        return 1;
    }
    gModule = RefModule_Create(aRefAllocator);
    if (!gModule) {
        RefObject_XDecRef(aRefAllocator);
        return 1;
    }
    return 0;
}

void
RefModule_Finalize(void)
{
    RefObject *refallocator;
    if (!gModule) {
        return;
    }
    refallocator = RefModule_GetAllocator(gModule);
    RefObject_DecRef(gModule);
    gModule = NULL;

    /* RefAllocatorForModule */
    if (RefObject_DecRef(refallocator)) {
        /* deleted: ok */
    } else {
        assert(0);
    }
}
